﻿/* ============================================================================
(c) Copyright 2012 Hewlett-Packard Development Company, L.P.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge,publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
============================================================================ */
using System;
using System.Collections.Generic;
using HPCloud.Objects.Utility;
using HPCloud.Objects.Domain.Compute;
using System.Collections.Specialized;
using System.Net.Http;
using HPCloud.Objects.Domain.Compute.Servers;
using System.Diagnostics.Contracts;
using System.Net.Http.Formatting;
using HPCloud.Objects.Domain.Compute.Servers.Actions;
using System.IO;

namespace HPCloud.Objects.DataAccess.Compute
{
    public class ServerRepository : BaseRepository, IServerRepository
    {
        public ServerRepository(RepositoryContext context) : base(context)
        { }
        #region Implementation of IServerRepository
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="action"></param>
//==================================================================================================
        public void ChangePassword(ChangePasswordAction action)
        {
            string absoluteURI                          = this.Context.ServiceDescription.Url + "/servers/" + action.ServerId + "/action";
            ObjectContent<ChangePasswordAction> content = new ObjectContent<ChangePasswordAction>(action, this.CreateFormatter());
            Uri uri                                     = new Uri(absoluteURI);

            using (HttpClient client = this.CreateHttpClient(null))
            {
                client.DefaultRequestHeaders.Remove("Accept");

                HttpRequestMessage request   = new HttpRequestMessage(HttpMethod.Post, uri);
                MediaTypeFormatter mtf       = this.CreateFormatter();
                request.Content              = content;
                HttpResponseMessage response = client.SendAsync(request).Result;

                if (!this.IsStatusNormal(response.StatusCode))
                {
                    throw ExceptionFactory.CreateException(response);
                }
                else
                {
                    //msg.EnsureStatusIsSuccessful();
                }
                client.Dispose();
                request.Dispose();
            }
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="action"></param>
//==================================================================================================
        public void Reboot(RebootAction action)
        {
            string absoluteURI                  = this.Context.ServiceDescription.Url + "/servers/" + action.ServerId + "/action";
            ObjectContent<RebootAction> content = new ObjectContent<RebootAction>(action, this.CreateFormatter());
            Uri uri                             = new Uri(absoluteURI);

            using (HttpClient client = this.CreateHttpClient(null))
            {
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
                client.DefaultRequestHeaders.Remove("Accept");

                MediaTypeFormatter mtf       = this.CreateFormatter();                
                request.Content              = content;
                HttpResponseMessage response = client.SendAsync(request).Result;

                if (!this.IsStatusNormal(response.StatusCode))
                {
                    throw ExceptionFactory.CreateException(response);
                }
                else
                {
                    //msg.EnsureStatusIsSuccessful();
                }
                client.Dispose();
                request.Dispose();
            }
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
//==================================================================================================
       public Log GetServerLog(GetServerLogAction action)
        {
            string absoluteURI                        = this.Context.ServiceDescription.Url + "/servers/" + action.ServerId + "/action";
            ObjectContent<GetServerLogAction> content = new ObjectContent<GetServerLogAction>(action, this.CreateFormatter());
            Uri uri                                   = new Uri(absoluteURI);

            HttpClient client = this.CreateHttpClient(null);
            
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
                client.DefaultRequestHeaders.Remove("Accept");

                MediaTypeFormatter mtf = this.CreateFormatter();
                request.Content = content;
                HttpResponseMessage response = client.SendAsync(request).Result;

                StreamReader reader = new StreamReader(response.Content.ReadAsStreamAsync().Result);
                Log log             = new Log();
                log.Content         = reader.ReadToEnd();
                return log;

                if (!this.IsStatusNormal(response.StatusCode))
                {
                    throw ExceptionFactory.CreateException(response);
                }
                else
                {
                    //msg.EnsureStatusIsSuccessful();
                }
                //client.Dispose();
                //request.Dispose();
           
            return null;       
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="action"></param>
//==================================================================================================
        void Rebuild(RebuildAction action)
        { }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="action"></param>
//==================================================================================================
        void Resize(ResizeAction action)
        {
            
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="action"></param>
//==================================================================================================
        void RevertResizeAction(RevertResizeAction action)
        {
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="action"></param>
//==================================================================================================
        void ConfirmResize(ConfirmResizeAction action)
        { }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="action"></param>
//==================================================================================================
        void CreateImage(CreateImageAction action)
        { }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="metadata"></param>
/// <returns></returns>
//==================================================================================================
        public MetaData SetMetadata(MetaData metadata, string serverId)
        {
            ObjectContent content = new ObjectContent(typeof(MetaData), metadata, this.CreateFormatter());
            string absoluteURI    = this.Context.ServiceDescription.Url + "/servers/" + serverId + "/metadata";

            return this.InvokeEndpoint<MetaData>(absoluteURI, content);        
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="serverId"></param>
/// <param name="key"></param>
//==================================================================================================
        public void DeleteMetadata(string serverId, string key)
        {
                 string absoluteURI = this.Context.ServiceDescription.Url + "/servers/" + serverId + "/metadata/" + key;
                 this.InvokeEndpoint(HttpMethod.Delete, absoluteURI, null, null);
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <returns></returns>
//==================================================================================================
        public List<Server> GetServers()
        {
            return this.GetServers(null, null, null, null, ServerStatus.Unknown);
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="name"></param>
/// <param name="changesSince"></param>
/// <param name="imageId"></param>
/// <param name="flavorId"></param>
/// <param name="status"></param>
/// <returns></returns>
//==================================================================================================
        public List<Server> GetServers(string name, Nullable<DateTime> changesSince, string imageId, string flavorId, ServerStatus status = ServerStatus.Unknown)
        {
            NameValueCollection nvc = new NameValueCollection();

            if (imageId != null)                nvc.Add("image", imageId);
            if (flavorId != null)               nvc.Add("flavor", flavorId);
            if (changesSince != null)           nvc.Add("changes-since", Convert.ToString(changesSince));
            if (status != ServerStatus.Unknown) nvc.Add("status", status.ToString());
            if (name != null)                   nvc.Add("name", name);

            string uri = this.Context.ServiceDescription.Url + "/servers/detail";

            try
            {
                this.MediaType       = DataAccess.MediaType.json;
                RootServerClass root =  this.InvokeEndpoint<RootServerClass>(HttpMethod.Get, uri, nvc, null); //.List.ToList<RootServerClass>();
                List<Server> servers = new System.Collections.Generic.List<Server>();

                for (int i = 0; i < root.servers.Length; i++) {
                    servers.Add(root.servers[i]);
                }
                return servers;                
            }
            catch (Exception)
            {
                return null;
            }
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="server"></param>
//==================================================================================================
        public Server SaveServer (NewServer server)
        {
            this.MediaType           = DataAccess.MediaType.json;
            SingleNewServerClass sns = new SingleNewServerClass();
            sns.server               = server;
            ObjectContent content    = new ObjectContent(typeof(SingleNewServerClass), sns, this.CreateFormatter());

            SingleServerClass sServer = this.InvokeEndpoint<SingleServerClass>(this.Context.ServiceDescription.Url + "/servers", content);
            return sServer.server;
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
//==================================================================================================
        public Server GetServerByURI(string serverURI)
        {
            return this.InvokeEndpoint<Server>(HttpMethod.Get, serverURI, null, null);
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
//==================================================================================================
        public Server GetServer(string serverId)
        {
            string absoluteURI = this.Context.ServiceDescription.Url + "/servers/" + serverId;
            try
            {
                this.MediaType = DataAccess.MediaType.json;
                return this.InvokeEndpoint<SingleServerClass>(HttpMethod.Get, absoluteURI, null, null).server;
            }
            catch (Exception)
            {
                return null;
            }
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="serverId"></param>
//==================================================================================================
        public void DeleteServer(string serverId)
        {
            this.MediaType     = DataAccess.MediaType.json;
            string absoluteURI = this.Context.ServiceDescription.Url + "/servers/" + serverId;
            this.InvokeEndpoint<Server>(HttpMethod.Delete, absoluteURI, null, null);
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="name"></param>
//==================================================================================================
        public void UpdateServer(Server server)
        {
            Contract.Assert(server.Id != null && server.Name != null);
            ObjectContent<Server> content = new ObjectContent<Server>(server, this.CreateFormatter());
            
            string absoluteURI = this.Context.ServiceDescription.Url + "/servers/" + server.Id;
            this.InvokeEndpoint(HttpMethod.Put, absoluteURI, null, content, null);
        }
        #endregion
    }
}
